/*
 * Copyright (c) 2011, Nikolaus Moll
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 * * Neither the name of the gradecalculator.net nor the
 *   names of its contributors may be used to endorse or promote products
 *   derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */
package net.gradecalculator.gui.qt.common.widgets;

import java.util.List;

import net.gradecalculator.core.interfaces.ICourse;
import net.gradecalculator.core.interfaces.IElectiveCourse;
import net.gradecalculator.core.interfaces.IPerformanceType;
import net.gradecalculator.core.interfaces.IStudyRegulations;
import net.gradecalculator.core.interfaces.results.IResult;
import net.gradecalculator.gui.qt.common.interfaces.IValidationListener;
import net.gradecalculator.gui.qt.common.layouts.VerySimpleLayout;
import net.gradecalculator.gui.qt.common.util.StringUtil;
import net.gradecalculator.gui.qt.common.util.ValidationUtil;
import net.miblounge.miglayout.qt.MigLayout;

import com.trolltech.qt.gui.QGroupBox;
import com.trolltech.qt.gui.QLabel;
import com.trolltech.qt.gui.QLineEdit;
import com.trolltech.qt.gui.QWidget;

public class CourseEditor extends QWidget implements IValidationListener {
	private enum CourseEditorMode { DEFAULT_EDITOR, SRDX_INDIVIDUAL, STUDENT };
	
	private final QLineEdit leName;
	private final QLineEdit leECTS;
	private final QLineEdit leHoursPerWeek;
	private final QLineEdit leSemester;
	private final QLineEdit leCourseNumber;
	private final QLineEdit leExamNumber;
	
	private final ICourse course;
	private final IStudyRegulations regulations;
	
	private CourseTypeSelector courseTypes;
	private PerformancesSelector gradedPerformances;
	private PerformancesSelector ungradedPerformances;
	
	private final CourseEditorMode mode;
	private final IResult examinationResult;

	public CourseEditor(final QWidget parent, final IStudyRegulations regulations, final ICourse course)
	{
		this(parent, regulations, course, null, CourseEditorMode.DEFAULT_EDITOR);
	}
	
	public CourseEditor(final QWidget parent, final IStudyRegulations regulations,final IElectiveCourse course, final IResult examinationResult)
	{
		this(parent, regulations, course, examinationResult, getIndividualMode(examinationResult));
	}

	private CourseEditor(final QWidget parent, final IStudyRegulations regulations,final ICourse course, final IResult examinationResult, final CourseEditorMode mode)
	{
		if (mode == CourseEditorMode.DEFAULT_EDITOR) {
			if (course instanceof IElectiveCourse) {
				throw new IllegalStateException("Individual course not allowed in default editor");
			}
		}
		else {
			if (!(course instanceof IElectiveCourse)) {
				throw new IllegalStateException("Individual course expected");
			}
		}
		this.regulations = regulations;
		this.mode = mode;
		this.examinationResult = examinationResult;
		this.course = course;

		final MigLayout layout = new MigLayout("", "[][grow,fill]15[grow]"); 
		setLayout(layout);
	
		leName = addLineEdit(layout, "Name:", "", "span, growx");
		leECTS = addLineEdit(layout, "ECTS:", "", "");
		
		if (mode != CourseEditorMode.SRDX_INDIVIDUAL) {
			leCourseNumber = addLineEdit(layout, "Course No:", "split", "growx, wrap");
		} else {
			leCourseNumber = null;
		}

		leHoursPerWeek = addLineEdit(layout, "Hours/week:", "", "");

		if (mode != CourseEditorMode.SRDX_INDIVIDUAL) {
			leExamNumber = addLineEdit(layout, "Exam No:", "split", "growx, wrap");
		} else {
			leExamNumber = null;
		}
		
		leSemester = addLineEdit(layout, "Semester:", "", "growx, wrap");

		if (mode != CourseEditorMode.SRDX_INDIVIDUAL) {
			layout.addWidget(createGroupType(), "span, growx, wrap");
			layout.addWidget(createGroupPerformances(), "span, growx, wrap");
		}
		
		if (mode == CourseEditorMode.STUDENT) {
			leECTS.setEnabled(false);
			leHoursPerWeek.setEnabled(false);
		}

		initCourse();
		revalidate();
	}

	private static CourseEditorMode getIndividualMode(final IResult examinationResult)
	{
		if (examinationResult == null) {
			return CourseEditorMode.SRDX_INDIVIDUAL;
		} else {
			return CourseEditorMode.STUDENT;
		}
	}
	
	public void setStartFocus()
	{
		leName.setFocus();
		leName.setSelection(0, leName.text().length());
	}
	
	protected QLineEdit addLineEdit(final MigLayout layout, final String label, final String labelConstraints, final String editConstraints)
	{
		layout.addWidget(new QLabel(tr(label)), labelConstraints);
		final QLineEdit result = new QLineEdit(this);
		layout.addWidget(result, editConstraints);
		result.textEdited.connect(this, "revalidate()");
		return result;
	}
	
	protected QGroupBox createGroupType()
	{
		final QGroupBox result = new QGroupBox(tr("Type"), this);
		
		final VerySimpleLayout outerLayout = new VerySimpleLayout(result);
		final QWidget typesContainer = new QWidget(result);
		outerLayout.setWidget(typesContainer);
		
		final MigLayout innerLayout = new MigLayout("", "[grow,fill]"); 
		typesContainer.setLayout(innerLayout);
		
		courseTypes = new CourseTypeSelector(result, regulations.getCourseTypes());
		innerLayout.addWidget(courseTypes, "wrap");
		
		result.setLayout(outerLayout);
		return result;
	}
	
	protected QGroupBox createGroupPerformances()
	{
		final QGroupBox result = new QGroupBox(tr("Performances"), this);

		final VerySimpleLayout outerLayout = new VerySimpleLayout(result);
		final QWidget performancesContainer = new QWidget(result);
		outerLayout.setWidget(performancesContainer);

		final MigLayout innerLayout = new MigLayout("", "[][grow,fill]"); 
		performancesContainer.setLayout(innerLayout);
		
		innerLayout.addWidget(new QLabel(tr("Graded:")), "top, gaptop 9");
		gradedPerformances = new PerformancesSelector(this, regulations.getPerformanceTypes());
		innerLayout.addWidget(gradedPerformances, "top, growx, wrap");

		innerLayout.addWidget(new QLabel(tr("Ungraded:")), "top, gaptop 9");
		ungradedPerformances = new PerformancesSelector(this, regulations.getPerformanceTypes()); 
		innerLayout.addWidget(ungradedPerformances, "top, growx, wrap");
		
		result.setLayout(outerLayout);
		
		return result;
	}
	
	private ICourse getUsedCourse()
	{
// TODO 
		//		if (mode == CourseEditorMode.STUDENT) {
//			CourseDescription result = examinationResult.getCourseDescription();
//			if (result == null) {
//				result = new CourseDescription();
//				examinationResult.setCourseDescription(result);
//				
//				result.setECTS(course.getECTS());
//				result.setHoursPerWeek(course.getHoursPerWeek());
//			}
//			return result;
//		}
//		
		return course;
	}

	private void initCourse()
	{
		final ICourse usedCourse = getUsedCourse();
		
		leName.setText(usedCourse.getName());
		leECTS.setText(String.valueOf(usedCourse.getECTS()));
		leHoursPerWeek.setText(String.valueOf(usedCourse.getHoursPerWeek()));
		leSemester.setText(String.valueOf(usedCourse.getSemester()));

		if (mode != CourseEditorMode.SRDX_INDIVIDUAL) {
			leCourseNumber.setText(String.valueOf(usedCourse.getCourseNumber()));
			leExamNumber.setText(String.valueOf(usedCourse.getExamNumber()));

			// TODO
			courseTypes.setCourseTypes(usedCourse.getType());
			gradedPerformances.setPerformances(usedCourse.getGradedPerformance());
			ungradedPerformances.setPerformances(usedCourse.getUngradedPerformance());
		}
	}

	public void apply() {
		final ICourse usedCourse = getUsedCourse();
		// TODO
//		if ((mode == CourseEditorMode.STUDENT) && (usedCourse instanceof CourseDescription)) {
//			examinationResult.setCourseDescription((CourseDescription)usedCourse);
//		}
//
//		usedCourse.setName(StringUtil.cleanString(leName.text()));
//		usedCourse.setECTS(Float.parseFloat(leECTS.text()));
//		usedCourse.setHoursPerWeek(Integer.parseInt(leHoursPerWeek.text().trim()));
//		usedCourse.setSemester(Integer.parseInt(leSemester.text().trim()));
//		
//		if (mode != CourseEditorMode.SRDX_INDIVIDUAL) {
//			usedCourse.setCourseNumber(Integer.parseInt(leCourseNumber.text().trim()));
//			usedCourse.setExamNumber(Integer.parseInt(leExamNumber.text().trim()));
//			usedCourse.setGradedPerformance(getGradedPerformance());
//			usedCourse.setUngradedPerformance(getUngradedPerformance());
//			usedCourse.setType(courseTypes.getCourseTypes());
//		}
	}

	public List<IPerformanceType> getGradedPerformance() {
		return gradedPerformances.getPerformances();
	}

	public List<IPerformanceType> getUngradedPerformance() {
		return ungradedPerformances.getPerformances();
	}

	@Override
	public void revalidate()
	{
		ValidationUtil.revalidate(parentWidget());
	}
	
	public boolean validate() {
		
		if (StringUtil.cleanString(leName.text()).equals("")) {
			return false;
		}

		// TODO check numbers
		if (mode != CourseEditorMode.SRDX_INDIVIDUAL) {
			// TODO
			if (!getGradedPerformance().isEmpty()){
				return true;
			}
			if (!getUngradedPerformance().isEmpty()){
				return true;
			}

			return false;
		} else {
			return true;
		}
	}


}
